package touchtrack.model.track;

import java.awt.Image;
import java.util.LinkedList;
import java.util.List;

import touchtrack.exception.IllegalDuplicationException;
import touchtrack.model.artist.Artist;
import touchtrack.model.artist.ArtistInterface;

/**
 * Track
 * 
 * Abstract class representing a track.
 * 
 * @author	MuMe09 team 6
 * 			http://mumetech.wordpress.com/
 */
public abstract class Track implements TrackInterface
{
	/**
	 * Constructs a Track object.
	 * 
	 * @param 	Artist artist
	 * @param 	String title
	 * @param	image
	 * @effect	Sets the artist.
	 * @effect	Sets the title.
	 * @effect	Sets the track image.
	 * @effect	Sets an empty list of track matches.
	 */
	public Track(Artist artist, String title, Image image)
	{
		this.setArtist(artist);
		this.setTitle(title);
		this.setImage(image);		
		this.trackMatches = new LinkedList<TrackMatch>();
	}
	
	/***************************************************************************
	 * 									Track type
	 ***************************************************************************/
	
	/**
	 * Checks whether this track is a "local track" or not.
	 * 
	 * @return	a boolean, what did you expect?
	 */
	public boolean isLocal()
	{
		// (awkward instanceof here, sorry)
		return (this instanceof LocalTrack);
	}
	
	/**
	 * Plays this track, if it's a local track.
	 * No support for external tracks yet.
	 */
	public void play()
	{
		if (isLocal())
			((LocalTrack)this).play();
	}
	
	/***************************************************************************
	 * 									Artist
	 ***************************************************************************/
	
	/**
	 * Returns the artist.
	 * 
	 * @return	Artist artist
	 */
	public Artist getArtist()
	{
		return artist;
	}
	
	/**
	 * Returns an artist interface (for the UI).
	 * 
	 * @return	ArtistInterface artist
	 */
	public ArtistInterface getArtistInterface()
	{
		return this.artist;
	}

	/**
	 * Sets the artist.
	 * 
	 * @param 	Artist artist
	 * @post	this.getArtist() == artist
	 */
	private void setArtist(Artist artist)
	{
		this.artist = artist;
	}
	
	/**
	 * Track artist.
	 */
	private Artist artist;
	
	/***************************************************************************
	 * 								Track title
	 ***************************************************************************/
	
	/**
	 * Returns the Track title.
	 * 
	 * @return	String title
	 */
	public String getTitle()
	{
		return title.trim();
	}

	/**
	 * Sets the Track title.
	 * 
	 * @param 	String title
	 * @post	this.getTitle() == title
	 */
	private void setTitle(String title)
	{
		this.title = title;
	}
	
	/**
	 * Track title.
	 */
	private String title;
	
	/***************************************************************************
	 * 								Track image
	 ***************************************************************************/
	
	/**
	 * Returns the Track image.
	 * 
	 * @return	String image
	 */
	public Image getImage()
	{
		return image;
	}

	/**
	 * Sets the Track image.
	 * 
	 * @param 	Image image
	 * @post	this.getImage() == image
	 */
	private void setImage(Image image)
	{
		this.image = image;
	}
	
	/**
	 * Track image.
	 */
	private Image image;
	
	/***************************************************************************
	 * 								Track summary
	 ***************************************************************************/
	
	/**
	 * Returns the Track summary.
	 * 
	 * @return	String summary
	 */
	public String getSummary()
	{
		return this.summary.trim();
	}

	/**
	 * Sets the Track summary.
	 * 
	 * @param 	String summary
	 * @post	this.getSummary() == summary
	 */
	public void setSummary(String summary)
	{    
		this.summary = summary;
	}
	
	/**
	 * Track title.
	 */
	private String summary;
	
	/***************************************************************************
	 * 								Similar tracks
	 ***************************************************************************/
	
	/**
	 * Adds similar track to list.
	 * 
	 * @param	Track t
	 * @param	float similarity
	 * @throws	IllegalDuplicationException
	 */
	public void addSimilarTrack(Track track, float similarity) 
		throws IllegalDuplicationException
	{
		TrackMatch match = new TrackMatch(this, track, similarity);
		this.addMatch(match);
		track.addMatch(match);
	}
	
	/**
	 * @param 	TrackMatch match
	 * @throws 	IllegalDuplicationException 
	 */
	public void addMatch(TrackMatch match) 
		throws IllegalDuplicationException
	{
		if (this.trackMatches.contains(match))
			throw new IllegalDuplicationException(match.toString());
		
		this.trackMatches.add(match);
	}
	
	/**
	 * Returns a list of interfaces to similar tracks.
	 * 
	 * @return	List<TrackInterface>
	 */
	public List<TrackInterface> getSimilarTracks()
	{
		List<TrackInterface> similarTracks = new LinkedList<TrackInterface>();
		
		for ( TrackMatch match : trackMatches )
			similarTracks.add(match.getOther(this));
		
		return similarTracks;
	}
	
	/**
	 * Returns the similarity between two tracks.
	 * 
	 * @param 	TrackInterface
	 * @return	float similarity
	 */
	public float getSimilarity(TrackInterface track)
	{
		if (track.equals(this)) return 100;
		
		// search all matches
		for ( TrackMatch match : trackMatches )
		{
			if (match.contains(track))
				return match.getSimilarity();
		}
		
		return 0;
	}
	
	/**
	 * @param 	TrackMatch match
	 */
	public void removeMatch(TrackMatch match)
	{
		this.trackMatches.remove(match);
	}
	
	/**
	 * Similar tracks.
	 */
	private List<TrackMatch> trackMatches;
	
	/***************************************************************************
	 * 							Removal
	 ***************************************************************************/
	
	/**
	 * Removes this track.
	 */
	public void remove()
	{
		// removes all matches
		for (TrackMatch t : trackMatches)
		{
			t.getOther(this).removeMatch(t);
		}
	}
	
	/***************************************************************************
	 * 							Java standard methods
	 ***************************************************************************/
	
	/**
	 * Compares Tracks.
	 * 
	 * @param	Object obj
	 * @return	boolean
	 */
	public boolean equals(Object obj)
	{
		if (obj instanceof Track) {
			Track t = (Track)obj;
			return t.getTitle().equals(this.title) && 
				(t.getArtist() == null || this.getArtist() == null || 
						t.getArtist().equals(this.getArtist()));
		}
		
		return false;
	}
	
	/**
	 * @return	String
	 */
	public String toString()
	{
		if (this.getArtist() == null)
			return this.getTitle();
		else
			return this.getArtist().getName() + " - " + this.getTitle();
	}
}